v1.0.0 — Kararlı Sürüm · Apache 2.0 · Açık Kaynak

Web için yazılmış
bir scripting dili.

Routing dile gömülü. DB bağlantısı kalıcı. WebSocket, SSE, parallel(), jobs::, template:: — hepsi tek binary içinde. Framework kurma, sadece yaz.

⇓ İndir — Ücretsiz Kod Örnekleri →
index.lk — gerçek zamanlı dashboard
use cache;
$conn = db::connect("mysql://root:@127.0.0.1/shop");

# REST — JSON API
route("GET", "/api/dashboard", function() use ($conn) {
    $ch = channel(3);
    parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM orders", [])); });
    parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT sum(total) FROM orders", [])); });
    parallel(function() use ($ch, $conn) { send($ch, db::col($conn, "SELECT count(*) FROM users", [])); });
    print(json::encode(["orders" => receive($ch), "revenue" => receive($ch), "users" => receive($ch)]));
});

# SSE — canlı bildirim akışı
route("SSE", "/events", function($sse) {
    $id = timer::every(3000, function() use ($sse) {
        sse::send($sse, json::encode(["t" => date::now()]), "tick");
    });
    sse::on($sse, "close", function() use ($id) { timer::cancel($id); });
});
Warm Start Runtime
WebSocket + SSE
parallel() + channel()
SQLite · MySQL · PostgreSQL
jobs:: + queue:: + cache::
Bytecode VM · 7.8× hız
Apache / nginx / standalone
Bir web uygulaması için gerekenler

LOOK, sunucu taraflı web geliştirme için tasarlanmış bir scripting dilidir. Routing, DB, eşzamanlılık, gerçek zamanlı bağlantılar, arka plan işler ve şablon motoru — hepsi tek binary içinde, sıfır bağımlılıkla.

Warm Start Runtime

Uygulama bir kez başlar. DB bağlantısı, route kayıtları, setup kodu — hepsi bellekte kalır. Her HTTP isteği sadece dispatch_routes() çalıştırır.

32 worker, 4.7 milyon istek, 10 dakika — 0 hata, 8 MB RAM.

🔀

Routing Dile Gömülü

route("GET", "/urun/{id}", fn) — bu bir kütüphane çağrısı değil, dilin çekirdeği. Router kurmak yok, config yok, middleware stack yok.

REST, WebSocket, SSE — hepsi aynı route() sözdizimi ile.

🚀

parallel() + channel()

Go goroutine felsefesi, web scripting dilinde. 3 DB sorgusunu aynı anda çalıştır, sonuçları receive() ile topla — toplam süre max(t₁, t₂, t₃).

Eşzamanlılık için ek runtime, ek kütüphane, ek öğrenme yok.

📦

Gerçek Zamanlı: WS + SSE

route("WS", "/chat", fn) — WebSocket, RFC 6455 tam uyumlu. route("SSE", "/events", fn) — Server-Sent Events, timer::every() ile birlikte.

500 eşzamanlı WebSocket bağlantısı, 72 saat, 0 bellek sızıntısı.

Performans
Gerçek sayılar, gerçek sunucu

looktest.tobiyo.com.tr · AlmaLinux 8 · MariaDB · 32 worker ile ölçüldü.

0
RPS
HTTP + VM, router
c=100, 0 hata
0
RPS
Hesaplama yoğun (fib40)
VM bytecode, c=100
0
RPS
Peak yük (c=1000)
200K istek, 0 hata
7.8
× hız
Bytecode VM speedup
interpreter'a göre
8
MB
Bellek (32 worker)
10 dakika, 4.7M istek
0
hata
72 saat WebSocket
500 eşzamanlı bağlantı

Tüm testler looktest.tobiyo.com.tr canlı ortamında wrk / ab ile ölçülmüştür. DB-bound endpoint'ler ~380 RPS — darboğaz MySQL RTT (~2.6ms), LOOK değil. WebSocket: 500 eşzamanlı bot, 72 saat RSS sabit.

Tek binary, tam runtime

Hiçbir şey kurmadan, hiçbir şeyi öğrenmeden doğrudan yazın.

Temel
🔀

Routing Dile Gömülü

route("GET", "/urun/{id}", fn) — REST, WS, SSE aynı sözdizimi. URL parametresi otomatik parse.

Temel
🗄️

MySQL · SQLite · PostgreSQL

Sıfır bağımlılık, wire protocol doğrudan implement. Aynı API: db::query / db::exec / db::col.

Eşzamanlılık
⚙️

parallel() + channel()

Go goroutine stili. Fan-out, pipeline, producer-consumer — kanal üzerinden. Blocking yok, callback yok.

Gerçek Zamanlı
🔌

WebSocket

route("WS", "/chat", fn) — RFC 6455, SHA-1+Base64 handshake. ws::broadcast() tüm bağlı istemcilere.

Gerçek Zamanlı
📡

SSE + timer::

route("SSE", "/events", fn) — Server-Sent Events. timer::every(3000, fn) ile periyodik push.

Arka Plan
📬

jobs:: — İş Kuyruğu

SQLite tabanlı kalıcı kuyruk. jobs::push / worker / run. Delayed jobs, retry, dead-letter. Process kapanınca kaybolmaz.

Arka Plan
📥

queue:: — FIFO Kuyruk

In-memory, thread-safe, isimlendirilmiş kuyruk. Request'ler arası veri aktarımı. queue::push / pop / peek / size.

Önbellek
🧠

cache:: — In-Memory Cache

TTL destekli, thread-safe singleton. Warm start'ta tüm worker'lar paylaşır. cache::get / set / has / flush.

Şablon
🎨

template:: — Şablon Motoru

Layout kalıtımı, partial include, {#each} döngüsü, {#if} koşulu. Svelte gibi — runtime yok, sadece sunucu render.

VM
🚀

Bytecode VM

AST → register-based bytecode → switch dispatch. Compute-heavy workload'da interpreter'a göre 7.8× hız artışı.

Modül
📧

mail:: — E-posta Gönderimi

Mailgun, SendGrid, Postmark destekli. mail::send / send_html. MAIL_PROVIDER env ile provider seçimi.

Geliştirici
🧪

Test + REPL + Package

look test — 10 assertion, before_each/after_each. look repl — interaktif. look install github.com/user/pkg.

Gerçek kodla tanışın
index.lk — REST API, auth, validatorTemel
$conn = db::connect("mysql://root:@127.0.0.1/blog");
use auth;
use validator;
use cache;

function admin_kontrol() {
    session::start();
    if (session::get("admin_id") == null) {
        response::status(401);
        print(json::encode(["ok" => false, "hata" => "Yetkisiz"]));
        return false;
    }
    return true;
}

route("GET", "/api/yazilar", function() use ($conn) {
    # 5 dakika cache — aynı veriyi defalarca DB'den çekme
    $data = cache::get("yazilar");
    if ($data == null) {
        $data = db::query($conn, "SELECT * FROM yazilar ORDER BY id DESC", []);
        cache::set("yazilar", $data, 300);
    }
    print(json::encode(["ok" => true, "data" => $data]));
});

route("POST", "/api/yazilar", function() use ($conn) {
    if (!admin_kontrol()) { return; }
    $v = validator::check(request::json(), [
        "baslik"  => ["required", "min:3", "max:200"],
        "icerik"  => ["required", "min:10"]
    ]);
    if (!$v["ok"]) { response::status(422); print(json::encode($v)); return; }
    $data = request::json();
    db::exec($conn, "INSERT INTO yazilar (baslik,icerik) VALUES (?,?)", [$data["baslik"], $data["icerik"]]);
    cache::delete("yazilar");   # cache invalidate
    print(json::encode(["ok" => true, "id" => db::last_id($conn)]));
});
chat.lk — Gerçek zamanlı chat, broadcast hubWebSocket
# Hub: tüm bağlantıların ortak yayın kanalı (setup fazında)
$hub = channel();

route("WS", "/chat", function($ws) use ($hub) {

    # Her bağlantı için bir goroutine: hub'dan dinle → bu client'a yaz
    parallel(function() use ($ws, $hub) {
        while (true) {
            $msg = receive($hub);
            if ($msg == null) { break; }
            ws::send($ws, $msg);
        }
    });

    # Mesaj gelince hub'a gönder → tüm clientlar duyar
    ws::on($ws, "message", function($data) use ($hub) {
        $p = json::decode($data);
        send($hub, json::encode(["from" => request::ip(), "msg" => $p["msg"]]));
    });

    ws::on($ws, "close", function() {
        log::info("Bağlantı kapandı — aktif: " . ws::clients());
    });
});

# Keepalive ping — her 30 saniyede tüm clientlara
timer::every(30000, function() {
    ws::broadcast(json::encode(["type" => "ping"]));
});
parallel.lk — 3 sorgu aynı anda, toplam süre max(t1,t2,t3)parallel()
$conn = db::connect("mysql://root:@127.0.0.1/shop");

route("GET", "/panel/ozet", function() use ($conn) {

    $ch = channel(3);   # 3 sonuç beklenecek

    parallel(function() use ($ch, $conn) {
        send($ch, db::col($conn, "SELECT count(*) FROM siparisler", []));
    });
    parallel(function() use ($ch, $conn) {
        send($ch, db::col($conn, "SELECT sum(toplam) FROM siparisler WHERE durum='odendi'", []));
    });
    parallel(function() use ($ch, $conn) {
        send($ch, db::col($conn, "SELECT count(*) FROM kullanicilar WHERE aktif=1", []));
    });

    # Tüm goroutine'ler bitmeden devam etmez
    $siparisler  = receive($ch);
    $gelir       = receive($ch);
    $kullanicilar = receive($ch);

    print(json::encode([
        "siparisler"   => $siparisler,
        "gelir"        => $gelir,
        "kullanicilar" => $kullanicilar
    ]));
});
sse.lk — Canlı bildirim akışı, periyodik pushSSE + timer::
$conn = db::connect("mysql://root:@127.0.0.1/shop");

# SSE: tarayıcı bağlandığında sürekli veri akışı gönderilir
route("SSE", "/canli/siparisler", function($sse) use ($conn) {

    # Her 2 saniyede yeni sipariş kontrolü
    $tick = timer::every(2000, function() use ($sse, $conn) {
        $yeni = db::query($conn,
            "SELECT * FROM siparisler WHERE olusturma > date_sub(now(), interval 5 second)", []);
        if (count($yeni) > 0) {
            $ok = sse::send($sse, json::encode($yeni), "yeni_siparis");
            if (!$ok) { timer::cancel($tick); }   # bağlantı kapandı
        }
    });

    # 30s keepalive — tarayıcı timeout etmesin
    $ping = timer::every(30000, function() use ($sse) {
        sse::send($sse, "keepalive", "ping");
    });

    sse::on($sse, "close", function() use ($tick, $ping) {
        timer::cancel($tick);
        timer::cancel($ping);
        log::info("SSE kapandı — aktif: " . sse::clients());
    });
});
jobs.lk — SQLite kalıcı kuyruk, retry, mail gönderimijobs::
use jobs;
use mail;

# Route: isteği anında yanıtla (1ms), işi kuyruğa at
route("POST", "/kayit", function() use ($conn) {
    $data = request::json();
    db::exec($conn, "INSERT INTO kullanicilar (email,ad) VALUES (?,?)",
             [$data["email"], $data["ad"]]);

    # max 3 deneme, hemen işle (delay_sec=0)
    jobs::push("hosgeldin_email", ["to" => $data["email"], "ad" => $data["ad"]], 3, 0);

    # 10 dakika sonra hatırlatma maili
    jobs::push("hatirlatma_email", ["to" => $data["email"]], 3, 600);

    print(json::encode(["ok" => true]));
});

# worker.lk — ayrı process (systemd servis olarak çalışır)
jobs::recover("hosgeldin_email");   # crash recovery

jobs::worker("hosgeldin_email", function($job) {
    $r = mail::send($job["payload"]["to"], "Hoş geldiniz!",
                    "Merhaba " . $job["payload"]["ad"] . ", kaydınız tamamlandı.");
    return $r["ok"];  # false → retry (max 3), sonra dead-letter
});

jobs::run(5000);   # 5 saniyede bir poll
blog.lk — Struct + template engine (sunucu taraflı render)template::
use template;

# Struct — Go stili, method yok, sadece veri
struct Yazi {
    id
    baslik
    icerik
    tarih
    begeni: 0
    yayinda: true
}

$tpl = env("VIEWS_DIR", "/app/views");

route("GET", "/blog", function() use ($conn, $tpl) {
    $rows = db::query($conn, "SELECT * FROM yazilar WHERE yayinda=1", []);
    print(template::render($tpl . "/blog/index", [
        "baslik"  => "Blog",
        "yazilar" => $rows
    ]));
});


# views/blog/index.html — sunucu taraflı, JS yok
# {#extends "views/layout/base"}
# {#block "content"}
# {#each $yazilar as $y}
#   <article>
#     <h2>{$y.baslik}</h2>
#     <p>{$y.tarih} · {$y.begeni} beğeni</p>
#     <div>{!$y.icerik}</div>
#   </article>
# {/each}
# {#empty}<p>Henüz yazı yok.</p>{/each}
# {/block}
PHP ile yan yana

Aynı iş, daha az kod, daha az sürpriz.

PHP index.php — login + veri çekme
<?php
// Global değişkenler her yerde erişilebilir
session_start();
$conn = new mysqli("localhost", "root", "", "blog");

if ($_SERVER["REQUEST_METHOD"] === "POST"
    && $_SERVER["REQUEST_URI"] === "/giris") {

    // XSS temizleme — unutunca açık kapı
    $email = htmlspecialchars($_POST["email"] ?? "");
    $sifre = $_POST["sifre"] ?? "";

    // Prepared statement — her seferinde tekrar
    $stmt = $conn->prepare("SELECT * FROM users WHERE email=?");
    $stmt->bind_param("s", $email);
    $stmt->execute();
    $user = $stmt->get_result()->fetch_assoc();

    if ($user && password_verify($sifre, $user["sifre_hash"])) {
        $_SESSION["user_id"] = $user["id"];
        header("Location: /panel");
    } else {
        http_response_code(401);
        echo json_encode(["ok" => false]);
    }
}

if ($_SERVER["REQUEST_METHOD"] === "GET"
    && $_SERVER["REQUEST_URI"] === "/yazilar") {

    $rows = $conn->query("SELECT * FROM yazilar")->fetch_all(MYSQLI_ASSOC);
    echo json_encode($rows);
}
$_GET / $_POST global Manuel XSS temizleme Her request'te DB bağlantısı bind_param boilerplate
LOOK index.lk — aynı işlev
use auth;

$conn = db::connect("mysql://root:@localhost/blog");
# Bir kez açılır — tüm isteklerde canlı kalır

route("POST", "/giris", function() use ($conn) {
    session::start();
    $d = request::json();

    $rows = db::query($conn,
        "SELECT * FROM users WHERE email=?", [$d["email"]]);
    # ? parametreli — SQL injection yok, XSS temizleme yok

    if (count($rows) == 0 ||
        !auth::verify($d["sifre"], $rows[0]["sifre_hash"])) {
        response::status(401);
        print(json::encode(["ok" => false]));
        return;
    }
    session::set("user_id", $rows[0]["id"]);
    response::redirect("/panel");
});

route("GET", "/yazilar", function() use ($conn) {
    $rows = db::query($conn, "SELECT * FROM yazilar", []);
    print(json::encode($rows));
});
request:: — sıfır global Prepared stmt otomatik DB bağlantısı kalıcı auth:: PBKDF2 dahil
Konu PHP LOOK
DB bağlantısı Her request yeni bağlantı Warm start — bir kez açılır
Global değişken $_GET, $_POST, $_SESSION... Yok — request:: / session::
Routing Framework (Laravel, Slim...) Dile gömülü — route()
SQL injection koruması Manuel bind_param db::query otomatik parametreli
Eşzamanlılık pcntl_fork / ext parallel() + channel() dilde
WebSocket Ratchet / Swoole gerekir route("WS",...) — dahil
Performans (router) ~500–2000 RPS (FPM) 8.276 RPS (VM, Apache bypass)
Üç kural, asla değişmez

Her yeni özellik bu üç ilkeye hizmet etmek zorunda — yoksa dile girmez.

🗺️
PHP gibi yükle
Dosyayı sunucuya at, Apache yönlendirsin — bitti. Hiçbir şey kurmak yok, hiçbir şeyi derlemek yok. Paylaşımlı hosting, VPS, Plesk — aynı iş akışı.
# GitHub Releases → binary indir cp look-fcgi /opt/look/ && chmod +x /opt/look/look-fcgi # → Apache .htaccess, systemd servis
Go gibi düşün
Temiz kapsam, açık bağımlılık, goroutine stili eşzamanlılık. use() ile ne girdiği bildirilir. Gizli global değişken yok, sürpriz yok.
route("GET", "/urun/{id}", function($id) use ($conn) { print(json::encode($row)); });
🔒
Framework kurma
Routing, DB, auth, cache, jobs, WebSocket, SSE, template — hepsi dilin içinde. Paket yöneticisi açma, dependency hell yok.
use jobs; # SQLite iş kuyruğu use cache; # in-memory TTL cache use mail; # Mailgun/SendGrid # Kurulum yok. Hepsi binary içinde.
Ne kadar derin?

LOOK'un tüm bileşenleri sıfır bağımlılıkla C++23 ile yazılmıştır.

Parser

Lexer + Parser + AST

Precedence-aware parser, tam operatör seti, string interpolation, SourceLocation ile hata konumu.

VM

Bytecode VM

AST → 3-adres register bytecode → switch dispatch. Compute workload'da 7.8× hız. Fallback: tree-walk interpreter.

Eşzamanlılık

ThreadPool + ConnPool

--workers N, per-request interpreter kopyası, per-DSN bağlantı havuzu. Hot reload: sıfır kesinti.

HTTP/1.1 + WebSocket + SSE

epoll (Linux), IOCP (Windows). RFC 6455 WS, SSE frame codec. Sınırsız eşzamanlı bağlantı.

DB

MySQL · SQLite · PostgreSQL

Wire protocol sıfırdan. Sürücü yok, ORM yok. Aynı db:: API, farklı DSN.

Dağıtım

CGI + FastCGI + HTTP

Apache/nginx FastCGI, standalone HTTP, CGI fallback. Tek binary, üç mod.

5 dakikada çalışır

Platform seçin:

  1. Binary'yi indir

    GitHub Releases'tan platforma uygun arşivi indir ve çıkart.

    tar -xzf look-linux-x86_64.tar.gz
  2. Binary'yi kopyala ve execute bit ver

    cp look-fcgi /opt/look/ && chmod +x /opt/look/look-fcgi
  3. look-fcgi'yi başlat

    systemd servisi yaz (bkz. Docs → FastCGI) veya doğrudan:

    look-fcgi --port 9000 --workers 8
  4. Versiyon doğrula

    look-fcgi version # LOOK 1.0.0 (linux/amd64)
  1. XAMPP kurun

    XAMPP zaten kuruluysa bu adımı atlayın.

  2. install.bat'ı yönetici olarak çalıştırın

    Binary'leri kopyalar, Apache'yi yapılandırır, Task Scheduler servisi kaydeder.

    install.bat --xampp C:\xampp
  3. XAMPP Apache'yi yeniden başlatın

    XAMPP Control Panel → Apache → Restart. http://localhost/ açın — çalışıyor.

  1. Extension'ı yükleyin

    Plesk → Extensions → ZIP Yükle → look-lang-1.0.0.zip

  2. Domain ekleyin

    LOOK → Domain Ekle → domain seç, worker sayısı, mod (fcgi / http) → Başlat.

  3. Bitti

    Terminal yok, SSH yok, config yok. systemd + nginx vhost otomatik oluşturuldu.

  1. Build image'ını çek

    Docker, LOOK binary'lerini derlemek için kullanılır. Ubuntu 24.04 ve AlmaLinux 8 için ayrı Dockerfile mevcuttur.

    docker build -f Dockerfile.linux-build -t look-builder .
  2. Binary'yi derle

    docker run --rm -v "${PWD}:/src" look-builder sh -c "cd /src/build-linux && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j4"
  3. Çıktı binary'si

    cpp/build-linux/look-fcgi # hazır binary

    AlmaLinux 8 (Plesk) için Dockerfile.almalinux8-build kullanın — glibc farkı nedeniyle Ubuntu binary AlmaLinux'ta çalışmaz.

İndir
Web geliştiricileri için düşünüldü

v1.0.0 · Apache 2.0 · Tüm platformlar için kararlı sürüm.

🐧 Linux — Ubuntu 22/24

Ubuntu 22.04 / 24.04. Apache veya nginx ile. glibc 2.31+.

⇓ GitHub Releases → Kurulum Rehberi

🐧 Linux — AlmaLinux 8

AlmaLinux 8 / RHEL 8. Plesk sunucuları için. glibc 2.17 uyumlu build.

⇓ GitHub Releases → Plesk Kurulumu

🪟 Windows

Windows 10/11 + XAMPP. IOCP — sınırsız bağlantı. Task Scheduler ile otomatik başlatma.

⇓ GitHub Releases → XAMPP Kurulum Rehberi

🖥️ Plesk Extension

Plesk 18+ için tek tıkla kurulum. Domain ekle, başlat — terminal yok, SSH yok.

⇓ look-lang-1.0.0.zip → GitHub →

🧩 VS Code Extension

Sözdizimi renklendirme, 30+ snippet, bracket matching. Tüm modüller dahil. v0.1.0

⇓ Marketplace'ten Kur → VSIX İndir (Manuel)

📦 Kaynak Kod

C++23, CMake 3.20+. Apache 2.0 lisansı. Katkı yapmak veya kendin derlemek için.

GitHub → codlook/look Tüm Sürümler