pxx
Pxx is a Pascal and C compiler*1. Written in pascal, it self-hosts and cross-compiles — x86-64, i386, ARM (32 and 64), riscv, xtensa, down to bare-metal ESP32.
This project was vibe coded*2. It started as a proof of concept, and got out of hand — the story is below*3.
It's a full pascal + C compiler, FPC- and C99-compatible. Nilpy, our python dialect, is staged*4. Not fully optimized yet — our code is about ~2x as slow as optimized compilers.
Why pascal*5? It happened to be the language i know best. It's a middle ground between being very C-like, yet applying memory-management features for ansistring, OOP and dynarrays — and proved a golden middle ground for the nilpy experiment.
Docs: documentation · compliance overview.
Read more
The story
It began with a nuisance: to use a C library from pascal, you hand-write a wrapper. Every time. Even though the C header already declares every type. So why not import that C header directly, and be done.
So i sat down, vibe coded. Pascal, self-hosting first. Then compile C, headers
included, and call straight in. An auto keyword that works out a variable's type
for you — a pointer to an iterable sqlite result set, say. Then the same behind
basic, then python syntax. Principle proved: we can detect types.
Then it kept working. Within a week, most of the proofs done (below). So i went down the hole. Premium anthropic account. Tickets. A test harness. Bug-driven development. Steer, babysit, grow the vibe baby.
Proofs of concept
The questions, that first week, and the answers:
- Auto-typing — import a library, declare a variable
auto, the compiler works out the type (a pointer to an iterable sqlite result set, say). Yes. - The same behind a python-like syntax. Yes.
- Import a system library straight from
/usr/include. Yes. - Compile with no system libraries, no libc, only syscalls. Yes — that became the platform layer (OS targets): a thin syscall shim, one for every frontend and target, down to bare-metal ESP32.
- Autoload and dynamically link from a bare
import/uses/include. Yes. - A C program that imports
math.pas, across CPU targets. Yes.
Auto-typing later folded back into the pascal dialect. Async became pascal language surface. See the PXX dialect.
nilpy
Python syntax, compiled through the same backend. Not a python runtime. Staged — it works, real apps run, it maps back onto the design concepts — but still in development, because pascal and C are the primary goal and those are proven. The cpython library ecosystem is out of scope. The language is not. More under languages.
FPC compatibility
Pascal syntax is largely FPC-compatible. FPC can bootstrap pxx. Details: FPC compatibility.
Why pascal
Don't know all of it. It's the language i'm most fluent in. 25 years. Also more C-like than people remember — managed data (ansistring, dynamic arrays), OOP, about halfway to C++.
Object Pascal
Pascal mixes plain C-level code with compiler-managed data (ansistring, dynamic arrays) and OOP. About halfway to C++, different route. One thing: pxx does not use any object pascal to compile itself. Its own source is plain, linear pascal. On purpose — fewer features used, fewer ways to miscompile the compiler.
Vibe coding
Built with an AI agent. The architecture shows it. As a human i'd have organized more into folders, and reached for OOP the moment it was available. The agent went the other way: plain pascal, big per-topic include files it can grep in one pass instead of hunting for the right source file. Humans keep source files short. An agent will take a 30,000-line include over searching subfolders. Different instincts. The codebase wears them.
It shows in the decisions too. Asked what a cdecl marker should mean on a
routine pxx compiles itself — three answers, all of them expensive — the reply
settled it in one line:
Decorators are decoration, and the convention is the target's by definition.
— Opus 5.0, on the xtensa calling convention
A calling-convention marker does not select an ABI. The target already defines one, so the marker decorates and nothing else. That turned a feature question into a smaller and better fix: make pxx's xtensa convention be the xtensa C ABI, on both sides, unconditionally — so pxx and gcc agree and no marker is involved at all.
Bug-driven development
Point the compiler at real-world code — a C library, a pascal unit, a python script. See what breaks. File it. Fix it. Repeat. Correctness is checked against the reference tools (gcc, fpc, cpython) as oracles. Goal: compile anything, match what the established compilers already do.