patch-prolog
A standalone Prolog compiler. plgc compiles an ISO-subset Prolog
program to a single native binary with zero runtime dependencies — no
Rust toolchain, no interpreter, no serialized clause database. Predicates
become native code via LLVM.
plgc build rules.pl -o my-linter # ~676K standalone binary
./my-linter --query "violation([field(id,integer)], Field, Reason)"
echo $? # 0 = no solutions (clean), 1 = solutions found
The compiled binary contains no clause interpreter — control flow is generated per predicate as native code, and only primitive services (heap, trail, unification, builtins, query parsing, output) come from a small runtime statically linked in. The result runs anywhere with libc/libm and nothing else.
The language semantics (ISO subset, the full builtin vocabulary, the embedded list stdlib, safety guarantees) are pinned by a 200-assertion integration corpus. The execution model is built on the architecture proven by patch-seq: LLVM IR text generation, clang linking, and a Rust runtime staticlib embedded in the compiler binary.
The toolchain
Three binaries share the engine:
| Binary | What it is |
|---|---|
plgc | The compiler — build, run, and check your Prolog. |
plgr | An interactive REPL that drives the compiler (never interprets). |
plgl | A Language Server (diagnostics, completion, hover, go-to-definition). |
Requirements
- To build the compiler: Rust (see
rust-toolchain.toml),just - To use
plgc: clang ≥ 15 (for linking) — no Rust required - To run compiled binaries: nothing (libc/libm only)
Quick start
just build # builds libplg_runtime.a then plgc
target/release/plgc build examples/deps.pl -o deps
./deps --query "needs(app, X)"
./deps --query "findall(D, needs(app, D), Ds)" --format text
Scripts work too:
#!/usr/bin/env plgc
greet(hello, world).
chmod +x greet.pl && ./greet.pl --query "greet(X, Y)" --format text
Commands
| Command | Purpose |
|---|---|
plgc build <in.pl>... [-o out] [--keep-ir] [--debug] | compile to a native executable (--debug: -O0 + DWARF) |
plgc run <in.pl>... --query "g(X)" | compile to a temp binary and run it (never interprets) |
plgc check <in.pl>... | parse + static analysis only |
plgc completions <shell> | shell completion scripts |
plgc prog.pl [args...] | script mode (shebang-friendly) |
Compiled binaries take --query "goal", --limit N,
--format json|text (default json) and exit with 0 no solutions ·
1 solutions · 2 query parse error · 3 runtime error. The step
ceiling (default 10,000, uncatchable) is tunable via PLG_MAX_STEPS.
The language
An ISO 13211-1 subset, with ISO conformance as the guide. A few minor, deliberate deviations and several safety extensions beyond ISO are documented in ISO_COMPLIANCE.md; the subset is defined by its omissions and its features.
Deliberate omissions: no modules, DCG, op/3, assert/retract, or
postfix operators.
Features:
- Full backtracking with first-argument indexing
- Cut, transparent through
,/;/->(ISO semantics) ->/;/\+/oncecatch/throwwith the ISO error-term taxonomyfindall/3,call/N,between/3- Checked i64 arithmetic with floored
mod - The standard order of terms
- ~60 builtins, plus a compiled-in list stdlib
(
member,append,length,reverse,nth0/1,last)
Deep recursion is safe: all control transfers are guaranteed tail
calls (musttail), so a million-deep recursive chain runs in
constant C stack.
Documentation
Source pages: Getting Started · Compiler Usage · Language Guide · Operators · Builtin & Stdlib Reference · Semantics & ISO Conformance · REPL Guide · LSP & Editor Guide · Examples · Architecture