A statically and flexibly type-inferred scripting language
with just-in-time compilation
prepoly is a statically type-checked, structurally typed scripting language with flexible type inference. The name contracts pre-typed and polymorphic: it runs like an interpreter, but every function is fully type-checked just before it executes, and most types are inferred rather than written. A program is run by a just-in-time compiler for native speed, or by an interpreter for the REPL and WebAssembly.
Quick start:
curl -L https://raw.githubusercontent.com/cordx56/prepoly/refs/heads/main/scripts/install.sh | sh- Type inference everywhere. Flexible inference means most code needs no annotations; types are resolved per function, just before it runs.
- Records and sum types under one
typekeyword. Methods are implemented withfun T.m(...): a firstselfparameter makes an instance method, otherwise it is static;Selfrefers to the type. - Structural subtyping with interface contracts.
type B: ArequiresBto provide every member ofA, checked at compile time; plain functions accept any value that has the members they use, with no inheritance. - Exhaustive pattern matching with
matchandif let. - Nullable and Result.
T?is narrowed byif;T!is aResult, witherror(x),expr!early-return propagation, and automaticOkwrapping.!on a nullable unwraps or returns null early (the return type gains?), and works at the top level and inmain, where a failure prints the error and exits. - Structural conversion.
T.from(v)for a record typeTyieldsT?— the record whenvstructurally has all ofT's fields, else null — soif let p = T.from(v)branches on the actual value. - References with inferred mutability. An unannotated parameter is passed by
reference and its mutability is inferred;
inferdeep-copies instead;ref(T)andref(mut(T))are explicit. Closures capture by mutable reference. - Tuples
[T, U], anonymous structural records, string interpolation, and both explicit and automatic numeric conversion. - A file-based module system where each file is a module and a leading
_marks a private name, plus a small standard library written in prepoly itself. - Experimental concurrency.
spawn(f),with(cown, f), andsync()are the primitives; the compiler infers ownership, never the programmer. - Tooling: an interactive REPL and an LSP server (
prepoly-lsp).
Read the documentation: a step-by-step tutorial,
per-feature guides, language references, and a browser playground, built from
book/. Every language feature also has a runnable example in
examples/, each checked by cargo test.
The native build links LLVM statically for the JIT. Rather than require a
system LLVM, the ./x wrapper downloads a prebuilt LLVM into ./llvm/ on first
use and runs cargo with it on the path. Use ./x in place of cargo:
./x cargo build --release # downloads LLVM on first run -> ./target/release/prepoly
./x cargo test --workspace
./x cargo clippy --workspace --all-targetsLLVM is needed only by the JIT. An interpreter-only build needs no LLVM and uses
plain cargo:
cargo build -p prepoly_driver --no-default-features # interpreter only, no LLVMprepoly also builds for wasm32-wasip1, where it runs through the interpreter.
prepoly path/to/file.pp # type-check and run (the LLVM JIT when available)
prepoly check path/to/file.pp # type-check only
prepoly repl path/to/file.pp # run a file through the interpreter
prepoly repl # interactive interpreter session
prepoly # no arguments: same interactive sessionA bare file argument is type-checked and then run on the JIT when it is built in,
otherwise on the interpreter. Each module's top-level statements run in dependency
order, then main is called if defined. The standard library is an implicit
prelude.
Sequential execution is the tested, supported path. Two sharp edges are worth knowing:
- Concurrency is experimental. Scheduling is unstructured, so code that must
observe a spawned task's results calls
sync()first. Treat it as a preview. - The JIT and interpreter agree across the language's tested surface, but a
few runtime-only features differ: file I/O and concurrency currently require
the native runtime rather than
prepoly repl.
Mozilla Public License 2.0. See LICENSE.