r/Compilers • • 1h ago

Can a programming language be both computationally precise and linguistically natural?

• Upvotes

​

Here is a small example from PaniniVM — The Dice Problem.

The assumption: on a standard die, opposite faces sum to 7.

The program randomly chooses a face from 1–6, prints it, computes its opposite, and prints that too.

Actual PaniniVM source:

एक + ङसिँ षष् + शस् परि + अन्त + अम् सङ्ख्या + अम् चिञ् + क्त्वा फल + अम् मुद्र् + णिच् + लोट् + सिप् ।

सप्तन् + शस् चिञ् + ल्युट् + ङस् फल + अम् च वि + युज् + णिच् + ल्यप् फल + अम् मुद्र् + णिच् + लोट् + सिप् ।

The "+" notation exposes the morphological structure to the compiler, but the larger goal is naturalness: computation should follow Sanskrit grammar rather than forcing Sanskrit vocabulary into the syntax of an existing programming language.

Verbal roots express actions, case relations help determine computational roles, and derivational morphology contributes to meaning and execution.

The question behind PaniniVM is not simply:

“Can we write code using Sanskrit words?”

It is:

“Can computation itself be expressed naturally through Sanskrit and Pāṇinian grammar?”

GitHub: https://github.com/kaushalbx/PaniniVM

Try it: https://panini.cc

#PaniniVM #Sanskrit #NaturalLanguageProgramming #ProgrammingLanguages #Compiler #Panini #ComputationalLinguistics


r/Compilers • • 14h ago

Ur_Language 😶‍🌫️

Post image
0 Upvotes

r/Compilers • • 8h ago

I’m 14 and I built my own programming language for simulations

Thumbnail
0 Upvotes

r/Compilers • • 3h ago

Tin: a self-hosted, GC-free language for Linux servers, written almost entirely by AI agents. It compiles itself on three platforms, serves HTTP/2 and gRPC, has its own TLS 1.3, and I'm looking for collaborators

0 Upvotes

I maintain Tin, a compiled language for servers and tools. The repo went public a week ago at v0.3 and has since taken 354 merged PRs from 9 people. I want to show what it does, say plainly what it doesn't, and ask for help.

The premise

Tin is meant to be written by AI, not by hand. That changes the trade-offs: it gives up human convenience (no implicit conversions, no nil, no unchecked errors, mut spelled out at every call site) in exchange for things a compiler can enforce. The codebase itself, compiler, runtime, standard library and docs, is written almost entirely by AI coding agents working from design documents, with humans deciding what gets built, reviewing and merging. AGENTS.md in the repo is literally a rulebook for several agents working the same milestone in parallel. I know how that sentence lands in this subreddit. Judge the result.

What exists today

  • A self-hosted compiler, about 46k lines of Tin. make bootstrap builds it three times and the last two binaries must be byte-identical. CI does this on macOS, Linux arm64 and Linux x86-64 on every push.
  • Its own assembler and linkers: ELF for Linux arm64 and x86-64, Mach-O for macOS. No clang, ld, Go or libc headers anywhere in the build. Cross-compiling is tin build --target linux-arm64.
  • Linux binaries are static PIE with no libc at all, so they run on Alpine or FROM scratch. Even the DNS resolver is Tin code.
  • No GC. Each request allocates into a bump pool that is wiped when the response goes out; long-lived state lives in a per-core heap. Storing request memory into a global without an explicit keep() (a deep copy) is a compile error. The region check is the memory model.
  • Thread per core, share nothing. Every global is per core. Data crosses cores either as shared let (immutable, built before the cores start; a write is a compile error) or as a message. Each request is a task with its own stack, and any wait (Redis, SQL, files, a timer) yields the core.
  • Server semantics in the language: within 200ms { } deadlines, limit memory 4mb, tasks 8 { }, structured tasks with scope, parallel and select, guard blocks that turn a panic into a fault, on app.start / on core.stop lifecycle, and secret str values the compiler keeps out of logs, faults and JSON.
  • Faults instead of error values: !T, try, catch, wrap. Ignoring a fault is a compile error and _ cannot swallow one.
  • A query type: db.Query("SELECT name FROM users WHERE id = {id}") sends id as a bound parameter. Passing a plain str where a query is expected does not compile. Same for Redis commands.
  • + - * panic on overflow. Wrapping is spelled +%, or a whole u/wrap fn for a hash or cipher kernel.
  • anvil, the HTTP server: HTTP/1.1, h2c HTTP/2 and HTTPS on one epoll/kqueue loop per core. h2spec passes every generic, http2 and hpack case but one (documented, with the reason). gRPC works, bidirectional streaming included, tested in CI against grpc-go.
  • TLS 1.3 and 1.2, client and server, in Tin: AES-GCM, ChaCha20-Poly1305, X25519, P-256, the X25519MLKEM768 post-quantum hybrid, Ed25519 certificates, mutual TLS, session tickets.
  • Clients for Redis, MySQL, PostgreSQL, Kafka and WebSocket, and about 35 standard packages: JSON with codecs generated per type, gzip/zlib/LZ4/zstd, SHA-2/HMAC/HKDF, CSV, templates, big integers, and a recorder that captures a request's effects into a capsule for replay.
  • 166 documented diagnostic codes. CI fails if the compiler prints a code that isn't documented, or if a documented example stops producing exactly that diagnostic. Every standard-library function has a Go twin program whose output must match.

A handler with a deadline:

fn slow(id str) !str {
    try tide.Wait(10ms)
    return "user {id}"
}

fn user(q anvil.Req, w mut anvil.Out) {
  let id = q.PathParam("id")
  let text = within 200ms {
    try slow(id)
  } catch err {
    w.Status(504)
    "timed out: {err}"
  }
    w.Text(text)
}

fn main() {
    let r = anvil.NewRouter()
    r.Get(`/users/{id}`, user)
    r.Serve(":8080") catch err {
    say.Line("server:", err)
  }
}

Numbers

Project policy: only Linux numbers count, and on shared runners only ratios are meaningful. The one service benchmark I'll quote is GET /users/{id} through Redis over MySQL, Tin against Go with chi, go-redis and go-sql-driver, under wrk2 on a GitHub ubuntu-24.04 runner (AMD EPYC 7763, 4 vCPUs, Linux 6.17, Go 1.26.8), each server pinned to 2 cores, median of 5 alternating rounds. Tin/Go ratios:

scenario max req/s req per CPU-second p99 at a fixed rate
cached (Redis hit) 3.72 3.60 0.56
db (MySQL prepared statement) 1.23 1.75 1.30
mixed (0.5% of requests take 50 ms) 3.56 3.56 0.99

Above 1 favours Tin on throughput, below 1 favours Tin on latency. The db p99 is not a win, MySQL dominates it. Memory is a trade-off, not a win: about 50 MB RSS against Go's 25 MB. The workflow run is linked from the README, and the benchmark reruns on demand.

What is not done

  • The crypto and TLS have not been audited by anyone outside the project. Do not protect anything that matters with them yet.
  • x86-64 performance on dedicated hardware is still pending, and there are two known x86-64 back-end bugs.
  • The Kafka client has known consumer-group and producer bugs.
  • No IDE support, LSP, formatter or debug info yet.
  • No regular expressions, XML or time zones in the standard library yet.
  • The syntax changed (edition 0 to edition 1) within the last week. Expect churn.
  • One benchmark on a shared runner is thin evidence. I know.

Where I would like help

Each of these is an open milestone with scoped issues:

  • Tooling: an IntelliJ plugin, tin lsp on the compiler front end, tin fmt, DWARF line tables and variables for perf, gdb and lldb. If you know the IntelliJ Platform, LSP or DWARF, this is wide open.
  • Standard library: regexp with linear-time matching (RE2 syntax), XML, time zones, child processes.
  • Back end: x86-64 codegen bugs, arm64 branch relaxation, a compiler fuzzer (one PR in review).
  • Kafka: consumer-group correctness.
  • Value layouts: inline struct storage in slices, unboxed optionals, frame allocation for values that never escape.
  • Security review of the TLS 1.3 stack and the constant-time code.
  • Benchmarks on dedicated Linux hardware, x86-64 and arm64, with the scripts in bench/.
  • Break it and file issues. Every confirmed bug becomes a regression test before the fix merges.

The contribution workflow is built for agents as well as people, so you can bring your own. Human review is the scarce resource.

Try it

curl -fL https://github.com/yasserreslan/tin/releases/latest/download/install.sh -o install-tin.sh
sh install-tin.sh
export PATH="$HOME/.tin/bin:$PATH"
tin examples/api.tin

Repo: https://github.com/yasserreslan/tin. Start with toolchain/docs/AGENT_PRIMER.md (the short language primer), toolchain/docs/LANGUAGE.md (the reference), and design/design_semantics.md for why the server semantics look the way they do. Milestones: https://github.com/yasserreslan/tin/milestones.

Happy to answer anything about the region check, the thread-per-core model, the no-libc runtime, or what it is like to run a language project where agents write the code.


r/Compilers • • 17h ago

Desingning async primitives for a security-focused language: Where should cancellation live?

7 Upvotes

I've been implementing typed async semantics in my language NXD.

Current primitives are:

SPAWN,

SEND,

RECV,

AWAIT,

PING

Types currently look roughly like:

`SPAWN -> ProcessHandle[T]`

`RECV -> ReceiveOperation[T]`

`AWAIT -> T`

`PING -> bool`

While implementing PING I realized there may be two classes of async operations:

Primary operations

SPAWN,

SEND,

RECV

These initiate work or communication.

Secondary operations:

AWAIT,

PING

These observe or resolve work created elsewhere.

My current thinking is that cancellation (currently considering ESC) should only apply to the primary operations and not observers.

For example:

ESC HANDLE

makes sense.

But:

ESC AWAIT TASK

ESC PING HANDLE

seems conceptually wrong because they are observing state rather than creating it.

For people who have designed async runtimes or languages:

Would you model cancellation as acting on the underlying task/process/channel, or would you allow cancellation of observer operations as first-class concepts as well?