POLYTONE — the AI-native programming language

Guide

Toolchain & WASM

ptc is the whole toolchain: run, test, check, build, plus tokenize/parse/ir for looking under the hood.

terminal
ptc check hello.pt
# OK — hello.pt typechecks

ptc ir hello.pt        # print the stack-machine IR
ptc tokenize hello.pt  # print the token stream

Since Sprint 51 ptc build compiles full-value programs: records, enums, collections, Text, match, generics, multi-file programs. Every reachable function becomes a real WASM function — control flow, calls, and recursion compile to WASM structure — while every value operation runs in the committed value runtime: the reference VM's own exec_simple compiled to WASM, so both sides share one semantics by construction. Since Sprint 52 the whole language compiles: closures dispatch through the module's function table via call_indirect, args()/env() and file I/O reach the host through four runtime imports, and copy-on-write moves run the VM's own fast paths:

setlist.pt
record Song:
    title: Text
    plays: Int

fn main() -> Void:
    let cutoff = 10
    let songs = [
        Song(title: "arrival", plays: 41),
        Song(title: "departure", plays: 7),
        Song(title: "overture", plays: 23),
    ]
    let hits = songs.filter(fn(s: Song) -> Bool = s.plays > cutoff)
    print(hits.map(fn(s: Song) -> Text = s.title).join(" · "))
    print("{hits.fold(0, fn(acc: Int, s: Song) -> Int = acc + s.plays)} plays")

The lambda captures cutoff, filter and map dispatch through the function table, and the compiled module prints exactly what ptc run prints. The differential suite is a total CI gate: every fixture must compile, stdout must match byte for byte, and runtime errors carry the same teaching message and source position on both sides. ptc build covers the whole language.

Since Sprint 53 the toolchain also measures itself: ptc bench runs the benchmark suite — ordinary POLYTONE programs under bench/ — and reports executed instructions (deterministic, machine-independent) plus wall time. --record keeps the history in bench/history.jsonl, --check gates CI on ops regressions, and optimizations land only with a benchmark that proves them:

bench/rebuild_chain.pt
import images

fn main() -> Void:
    mut img = images.canvas(64, 64, 0, 0, 0)
    mut i = 0
    while i < 4000:
        img = images.set_pixel(img, i % 64, (i * 7) % 64, i % 256, (i * 3) % 256, (i * 5) % 256)
        i = i + 1
    let bytes = images.to_ppm_bytes(img)
    match images.get_pixel(img, 63, 41):
        case Some((r, g, b)):
            print("rebuild_chain: {bytes.len()} bytes, probe {r} {g} {b}")
        case None:
            print("rebuild_chain: probe out of bounds")